#include "Task.hpp"
#include "log.hpp"
#include <ctime>
#include <cstdlib>
#include <cassert>
#include <unistd.h>

static const int g_process_num = 5;   // 子进程个数

ssize_t WaitCommand(int fd, uint32_t& command)
{
    ssize_t n = read(fd, &command, sizeof(uint32_t));
    return n;
}

void DistributeTask(int id, int fd, int command)
{
    ssize_t n = write(fd, &command, sizeof(command));
    assert(n);
    (void)n;
}

int main()
{
    load();   // 加载任务

    int pipefd[2] = { 0 };   
    // 记录子进程编号和对应写端文件描述符
    std::vector<std::pair<pid_t, int>> slot;  

    // 开始for循环创建子进程
    for(int i = 0; i < g_process_num; ++i)
    {
        // 创建匿名管道
        int n = pipe(pipefd);

        if(n < 0)
        {
            logMessage(FATAL, "Pipe error!\n");
            exit(1);
        }

        // 创建子进程
        pid_t id = fork();

        // 子进程创建失败
        if(id < 0)
        {
            logMessage(FATAL, "Fork error!\n");
            exit(2);
        }
        else if(id == 0)  // 子进程代码
        {
            close(pipefd[1]);   // 关闭写端文件描述符

            while(true)
            {
                uint32_t command = 0;    // 命令编号
                ssize_t n = WaitCommand(pipefd[0], command);  // 获取命令编号

                // 判断获取指令是否成功，成功就运行对应任务
                
                // 指令编号读取成功
                if(n > 0)   
                {
                    trace_back[command]();
                }
                else if(n == 0)  // 写端关闭
                {
                    logMessage(DEBUG, "Father process close, me close!\n");
                    break;
                }
                else  // 读取失败
                {
                    logMessage(ERROR, "Get command error!\n");
                }
            }

            close(pipefd[0]);   // 关闭读端文件描述符
            exit(0);
        }

        // 此处为父进程代码
        close(pipefd[0]);   // 读端关闭
        slot.emplace_back(id, pipefd[1]);    // 建立子进程id和写端文件描述符的映射关系
    } 
    
    // 种下随机数种子
    srand((unsigned int)time(NULL));  

    int select = 0;

    // 父进程代码，指定进程并执行
    while(true)
    {
        std::cout << "##############################################" << std::endl;
        std::cout << "#########  1.choice  2.show  3.quit  #########" << std::endl;
        std::cout << "##############################################" << std::endl;

        std::cout << "Please select: > " << std::flush;
        std::cin >> select;

        if(select == 1) 
        {
            int command = 0;
            std::cout << "Please input the command that will be run: > " << std::endl;
            std::cin >> command;

            int index = rand() % g_process_num;   
            DistributeTask(slot[index].first, slot[index].second, command);    // 执行任务派发函数
        }
        else if(select == 2)
        {
            show();
        }
        else if(select == 3)
        {
            printf("Father process exit!\n");
            break;
        }
        else
        {
            printf("Input an error select!\n");
        }
        
        usleep(1000);
    }

    // 关闭父进程的每个写端文件描述符
    for(const auto& iter : slot)
    {
        close(iter.second);
    }

    // 逐个等到子进程退出
    for(const auto& iter : slot)
    {
        close(iter.first);
    }

    return 0;
}